package org.myspringframework.utils;

import org.myspringframework.context.annotation.Component;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.net.URL;
import java.util.HashSet;
import java.util.Set;

public class ClassUtils {

    public static ClassLoader getDefaultClassLoader() {
        ClassLoader cl = null;
        try {
            cl = Thread.currentThread().getContextClassLoader();
        }
        catch (Throwable ex) {
            // Cannot access thread context ClassLoader - falling back to system class loader...
        }
        if (cl == null) {
            // No thread context class loader -> use class loader of this class.
            cl = ClassUtils.class.getClassLoader();
        }
        return cl;
    }

    /**
     * 检查指定的类是否为cglib生成的类。
     */
    public static boolean isCglibProxyClass(Class<?> clazz) {
        return (clazz != null && isCglibProxyClassName(clazz.getName()));
    }

    /**
     * 通过检查指定的类名判断是否为cglib生成的类。
     */
    public static boolean isCglibProxyClassName(String className) {
        return (className != null && className.contains("$$"));
    }

    public static Set<Class<?>> scanPackageByAnnotation(String basePackage, Class<?> annotationClass) {
        //获取当前class文件夹的路径
        URL url = Thread.currentThread().getContextClassLoader().getResource("");
        //将.替换为/
        basePackage = basePackage.replace(".", "/");
        String classPath=url.toString().replace("file:/","");
        //如果当前为test,将test-classes替换为class
        if (classPath.contains("test-classes")){
            classPath=classPath.replace("test-classes","classes");
        }
        classPath=classPath+basePackage;
        //找到包下的所有class
        Set<Class<?>> allClasses = findAllClasses(new File(classPath));

        //判断该类是否有该注解
        Set<Class<?>> result=new HashSet<>();
        for (Class<?> oneClass : allClasses) {
            if (hasAnnotation(oneClass,annotationClass)){
                result.add(oneClass);
            }
        }
        return result;
    }

    //判断一个类下是否有注解
    public static boolean hasAnnotation(Class<?> oneClass,Class<?> annotationClass) {
        Annotation[] declaredAnnotations = oneClass.getDeclaredAnnotations();
        //获取该类的所有注解
        for (Annotation declaredAnnotation : declaredAnnotations) {
            if (declaredAnnotation.annotationType()== Documented.class||declaredAnnotation.annotationType()==Retention.class||declaredAnnotation.annotationType()== Target.class){
                continue;
            }else{
                if (declaredAnnotation.annotationType()==annotationClass){
                    //判断这个注解是不是目标注解
                    return true;
                }else {
                    //看看这个注解上的注解是否有目标注解
                    boolean b = hasAnnotation(declaredAnnotation.annotationType(), annotationClass);
                    if (b){
                        return true;
                    }
                }
            }
        }
        return false;
    }


    //递归扫描指定路径下的文件，获取.class文件
    private static Set<Class<?>> findAllClasses(File file){
        HashSet<Class<?>> classes = new HashSet<>();
        File[] files=file.listFiles();
        for (File f:files){
            if (!f.isDirectory()){
                //不是文件夹
                String fileName = f.getName();
                if (fileName.endsWith(".class")){
                    //获取文件路径
                    String path = f.getPath();
                    String classPath = parseClassPath(path);
                    try {
                        //反射加载class
                        Class<?> aClass = Class.forName(classPath);
                        classes.add(aClass);
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    }
                }
            }else {
                //为文件夹，递归
                classes.addAll(findAllClasses(f));
            }
        }
        return classes;
    }

    //将.class文件的路径转化为类的全路径 xx.xx.Book.class
    private static String parseClassPath(String classPath){
        int i = classPath.indexOf("classes\\");
        classPath = classPath.substring(i + 8,classPath.length()-6);
        classPath=classPath.replace("\\",".");
        return classPath;
    }
}